package com.mar.meclient.bt.impl;

import java.io.IOException;
import java.util.Hashtable;

import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;

import com.mar.meclient.bt.BTInquiryListener;
import com.mar.meclient.bt.IBluetoothConnectionHandler;
import com.mar.meclient.bt.IBluetoothIOHandler;

import net.java.dev.marge.entity.config.MargeDefaults;
import net.java.dev.marge.inquiry.DeviceDiscoverer;
import net.java.dev.marge.inquiry.InquiryListener;
import net.java.dev.marge.inquiry.ServiceDiscoverer;
import net.java.dev.marge.inquiry.ServiceSearchListener;

public class BluetoothConnectionHandler implements IBluetoothConnectionHandler {
	private Hashtable devicesFound;
	
	//------------ OFICIAL CONNECTION METHODS -------------------------//
	
	public BluetoothConnectionHandler() {
	}
	
	/* (non-Javadoc)
	 * @see com.mar.meclient.bt.IBluetoothConnectionHandler#startInquiry(com.mar.meclient.bt.BTInquiryListener)
	 */
	public void startInquiry(BTInquiryListener btIquiryListenerr) throws BluetoothStateException{
		devicesFound = new Hashtable();
		DeviceDiscoverer.getInstance().startInquiryGIAC(new InternalInquiryListener(btIquiryListenerr));
	}
	
	/* (non-Javadoc)
	 * @see com.mar.meclient.bt.IBluetoothConnectionHandler#stopInquiry()
	 */
	public void stopInquiry() throws BluetoothStateException{
		DeviceDiscoverer.getInstance().cancelInquiry();
	}
	
	/* (non-Javadoc)
	 * @see com.mar.meclient.bt.IBluetoothConnectionHandler#connectTo(java.lang.String)
	 */
	public IBluetoothIOHandler connectTo(String remoteDevice) throws IOException, BluetoothStateException{
		// check preconditions
		if ( devicesFound == null )
			throw new IllegalStateException("startInquiry() should be called before connect to a device");
		RemoteDevice remoteService = (RemoteDevice) devicesFound.get(remoteDevice);
		if ( remoteDevice == null )
			throw new IllegalArgumentException("There is no remote device available for label:"+remoteDevice);
       
		// potentially long operation
		InternalServiceSearchListener serviceSearcher = new InternalServiceSearchListener();
		
		// creating IO handler
		ServiceRecord serviceRecord = serviceSearcher.findService(remoteService);
		//TODO: remove useless comments.
//		try {
//			Thread.sleep(2000);
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
		
//		ClientConfiguration clientConfig = new ClientConfiguration(serviceRecord, new DefaultCommunicationListener());
		return new BluetoothIOHandler(serviceRecord);
	}
	
   //-------------------------- IMPLEMENTAION ---------------------------------// 

	private class InternalInquiryListener implements InquiryListener{
		private final BTInquiryListener btInquiryListener;
		public InternalInquiryListener(BTInquiryListener lsnt){
			this.btInquiryListener = lsnt;
		}
		public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass deviceClass) {
			devicesFound.put(remoteDevice.getBluetoothAddress(), remoteDevice);
			btInquiryListener.deviceFound(remoteDevice.getBluetoothAddress());
		}

		public void inquiryCompleted(RemoteDevice[] devices) {
			//TODO: what could be done with devices?
			btInquiryListener.inquiryCompleted();
		}

		public void inquiryError() {
			//TODO: handle!			
		}
	}
	
	private class InternalServiceSearchListener implements ServiceSearchListener{
		private ServiceRecord availableService = null;
		private Object lock = new Object();
		
		public synchronized ServiceRecord findService(RemoteDevice remoteDevice) throws BluetoothStateException{
			try {
				ServiceDiscoverer.getInstance().startSearch(
						MargeDefaults.DEFAULT_UUID_ARRAY, remoteDevice, this);
				synchronized (lock) {
					lock.wait();
				}
			} catch (InterruptedException e) {
				//TODO: handle
				e.printStackTrace();
			} catch (BluetoothStateException e) {
				throw e;
			} finally {
				return availableService;
			}
		}
		
		public void deviceNotReachable() {
			//lock.notify();
		}

		public void serviceSearchCompleted(RemoteDevice device,
				ServiceRecord[] serviceRecords) {
			//TODO: extract this method to BluetoothConnectionHandler
			if ( serviceRecords.length > 0 ){
				availableService = serviceRecords[0];
			}
			synchronized(lock){
				lock.notify();
			}
		}

		public void serviceSearchError() {
			//lock.notify();
		}
	}
}
